use "helper.sml" ;
use "tagparser.sml" ;

exception ErrorBadExpressionType of Expr ; (* bug *)
exception ErrorMisplacedConstruct of Expr ; (* bad input string *)

signature SEMANTIC_ANALYSIS =
sig
	val removeNestedDefine : Expr -> Expr;
	val boxSet : Expr -> Expr;
	val annotateTC : Expr -> Expr;
	val lexicalAddressing : Expr -> Expr ;
	val semanticAnalysis : Expr -> Expr ;
end;

(***************************************************************************************
  												 						SEMANTIC ANALYSIS
***************************************************************************************)

structure SemanticAnalysis : SEMANTIC_ANALYSIS =
struct

	fun	flattenSequences(Seq(expressions)) = Seq(flattenSequencesRemoveBegins(expressions))
	|	flattenSequences(e) = flattenSequencesTreeWalk(e)

	and	flattenSequencesRemoveBegins([]) = []
	|	flattenSequencesRemoveBegins(Seq(heads) :: tail) = flattenSequencesRemoveBegins(heads) @ flattenSequencesRemoveBegins(tail)
	|	flattenSequencesRemoveBegins(head :: tail) = flattenSequences(head) :: flattenSequencesRemoveBegins(tail)

	and	flattenSequencesTreeWalk(If(test, resTrue, resFalse)) = If(flattenSequences(test), flattenSequences(resTrue), flattenSequences(resFalse))
	|	flattenSequencesTreeWalk(Abs(args, body)) = Abs(args, flattenSequences(body))
	|	flattenSequencesTreeWalk(AbsOpt(args, argOpt, body)) = AbsOpt(args, argOpt, flattenSequences(body))
	|	flattenSequencesTreeWalk(AbsVar(argList, body)) = AbsVar(argList, flattenSequences(body))
	|	flattenSequencesTreeWalk(App(f, args)) = App(flattenSequences(f), map flattenSequences args)
	|	flattenSequencesTreeWalk(Or(expressions)) = Or(map flattenSequences expressions)
	|	flattenSequencesTreeWalk(Set(name, value)) = Set(flattenSequences(name), flattenSequences(value))
	|	flattenSequencesTreeWalk(Def(name, value)) = Def(flattenSequences(name), flattenSequences(value))
	(* debugging START *)
	|	flattenSequencesTreeWalk(e as Seq(_)) = raise ErrorBadExpressionType(e)
	(* debugging END *)
	|	flattenSequencesTreeWalk(e) = e ;



	fun	removeNestedDefine(e) = removeNestedDefine'(flattenSequences(e))

	and	removeNestedDefine'(Abs(args, body as Seq(Def(_, _) :: _))) = Abs(args, removeNestedDefineConvertDefine(body))
	|	removeNestedDefine'(Abs(args, body)) = Abs(args, removeNestedDefine'(body))
	|	removeNestedDefine'(AbsOpt(args, optArg, body as Seq(Def(_, _) :: _))) = AbsOpt(args, optArg, removeNestedDefineConvertDefine(body))
	|	removeNestedDefine'(AbsOpt(args, optArg, body)) = AbsOpt(args, optArg, removeNestedDefine'(body))
	|	removeNestedDefine'(AbsVar(argList, body as Seq(Def(_, _) :: _))) = AbsVar(argList, removeNestedDefineConvertDefine(body))
	|	removeNestedDefine'(AbsVar(argList, body)) = AbsVar(argList, removeNestedDefine'(body))
	|	removeNestedDefine'(Def(name, value)) = Def(name, removeNestedDefine'(value))
	|	removeNestedDefine'(e) = removeNestedDefineTreeWalk(e)

	and	removeNestedDefineTreeWalk(If(test, resTrue, resFalse)) =
			If(
				removeNestedDefine(test),
				removeNestedDefine(resTrue),
				removeNestedDefine(resFalse)
			)
	|	removeNestedDefineTreeWalk(App(f, args)) = App(removeNestedDefine'(f), map removeNestedDefine' args)
	|	removeNestedDefineTreeWalk(Seq(expressions)) = Seq(map removeNestedDefine' expressions)
	|	removeNestedDefineTreeWalk(Or(expressions)) = Or(map removeNestedDefine' expressions)
	|	removeNestedDefineTreeWalk(Set(name, value)) = Set(removeNestedDefine'(name), removeNestedDefine'(value))
	|	removeNestedDefineTreeWalk(e as Def(_, _)) = raise ErrorMisplacedConstruct(e)
	(* debugging START *)
	|	removeNestedDefineTreeWalk(e as Abs(_,_)) = raise ErrorBadExpressionType(e)
	|	removeNestedDefineTreeWalk(e as AbsOpt(_, _, _)) = raise ErrorBadExpressionType(e)
	|	removeNestedDefineTreeWalk(e as AbsVar(_, _)) = raise ErrorBadExpressionType(e)

	|	removeNestedDefineTreeWalk(e as VarFree(_)) = raise ErrorBadExpressionType(e)
	|	removeNestedDefineTreeWalk(e as VarParam(_, _)) = raise ErrorBadExpressionType(e)
	|	removeNestedDefineTreeWalk(e as VarBound(_, _, _)) = raise ErrorBadExpressionType(e)

	|	removeNestedDefineTreeWalk(e as AppTP(_, _)) = raise ErrorBadExpressionType(e)
	(* debugging END *)
	|	removeNestedDefineTreeWalk(e) = e

	and	removeNestedDefineConvertDefine(Seq(expressions)) = removeNestedDefineGetAllDefines(expressions, [], removeNestedDefineMakeLambda)
	|	removeNestedDefineConvertDefine(e) = raise ErrorBadExpressionType(e)

	and	removeNestedDefineGetAllDefines([], defines, continuation) = continuation(defines, [])
	|	removeNestedDefineGetAllDefines((head as Def(_, _)) :: tail, defines, continuation) =
			removeNestedDefineGetAllDefines(tail, head :: defines, continuation)
	|	removeNestedDefineGetAllDefines(expressions, defines, continuation) = continuation(defines, expressions)

	and	removeNestedDefineMakeLambda(defines, expressions) =
			App(
				Abs(
					removeNestedDefineGetVarNames(defines),
					Seq(map removeNestedDefine' (removeNestedDefineMakeSets(defines) @ expressions))
					),
				removeNestedDefineMakeDummies(length(defines))
			)

	and	removeNestedDefineGetVarNames(defines) =
			rev(
				map
					(fn	(Def(Var(name), _)) => name
					|	(e) => raise ErrorBadExpressionType(e))
					defines
			)

	and removeNestedDefineMakeSets(defines) =
			rev(
				map
					(fn	(Def(name, value)) => Set(name, value)
					|	(e) => raise ErrorBadExpressionType(e))
					defines
			)

	and	removeNestedDefineMakeDummies(0) = []
	|	removeNestedDefineMakeDummies(n) = Const (Bool false) :: removeNestedDefineMakeDummies(n-1) ;


	(* this is done to reduce the cases needed to handle, since absvar is just absopt with 0 regular args *)
	fun	convertAbsVarToAbsOpt(AbsVar (argList, body)) = AbsOpt ([], argList, convertAbsVarToAbsOpt(body))
	|	convertAbsVarToAbsOpt(e) = convertAbsVarToAbsOptTreeWalk(e)

	and	convertAbsVarToAbsOptTreeWalk(If (test, resTrue, resFalse)) =
			If(convertAbsVarToAbsOpt(test), convertAbsVarToAbsOpt (resTrue), convertAbsVarToAbsOpt(resFalse))
	|	convertAbsVarToAbsOptTreeWalk(Abs (args, body)) = Abs (args, convertAbsVarToAbsOpt(body))
	|	convertAbsVarToAbsOptTreeWalk(AbsOpt (args, argOpt, body)) = AbsOpt (args, argOpt, convertAbsVarToAbsOpt(body))
	|	convertAbsVarToAbsOptTreeWalk(App (f, args)) = App (convertAbsVarToAbsOpt(f), map convertAbsVarToAbsOpt args)
	|	convertAbsVarToAbsOptTreeWalk(AppTP (f, args)) = AppTP (convertAbsVarToAbsOpt(f), map convertAbsVarToAbsOpt args)
	|	convertAbsVarToAbsOptTreeWalk(Seq (expressions)) = Seq (map convertAbsVarToAbsOpt expressions)
	|	convertAbsVarToAbsOptTreeWalk(Or (expressions)) = Or (map convertAbsVarToAbsOpt expressions)
	|	convertAbsVarToAbsOptTreeWalk(Set (name, value)) = Set (convertAbsVarToAbsOpt(name), convertAbsVarToAbsOpt(value))
	|	convertAbsVarToAbsOptTreeWalk(Def (name, value)) = Def (convertAbsVarToAbsOpt(name), convertAbsVarToAbsOpt(value))
	(* debugging START *)
	|	convertAbsVarToAbsOptTreeWalk(e as AbsVar (_,_)) = raise ErrorBadExpressionType(e)
	(* debugging END *)
	|	convertAbsVarToAbsOptTreeWalk(e) = e ;


	fun	boxSet(e) = flattenSequences(boxSetTreeWalk(e))

	and	boxSetTreeWalk(e as Const(_)) = e
	|	boxSetTreeWalk(e as Var(_)) = e
	|	boxSetTreeWalk(If(test, resTrue, resFalse)) = If(boxSetTreeWalk(test), boxSetTreeWalk(resTrue), boxSetTreeWalk(resFalse))
	|	boxSetTreeWalk(App(f, args)) = App(boxSetTreeWalk(f), map boxSetTreeWalk args)
	|	boxSetTreeWalk(Seq(expressions)) = Seq(map boxSetTreeWalk expressions)
	|	boxSetTreeWalk(Or(expressions)) = Or(map boxSetTreeWalk expressions)
	|	boxSetTreeWalk(Def(name, value)) = Def(boxSetTreeWalk(name), boxSetTreeWalk(value))
	|	boxSetTreeWalk(Set(name, value)) = Set(boxSetTreeWalk(name), boxSetTreeWalk(value))
	|	boxSetTreeWalk(e) = boxSetDoLambda(e)

	and	boxSetDoLambda(Abs(args, body)) =
			Abs(args, boxSetScanClosure(boxSetTreeWalk(body), rev args))
	|	boxSetDoLambda(AbsOpt(args, argOpt, body)) =
			AbsOpt(args, argOpt,boxSetScanClosure(boxSetTreeWalk(body), rev (args @ [argOpt])))
	(*|	boxSetDoLambda(AbsVar(argList, body)) =
			AbsVar(argList, boxSetScanClosure(boxSetTreeWalk(body), rev [argList]))*)
	(* debugging START *)
	|	boxSetDoLambda(e as AbsVar(_, _)) = raise ErrorBadExpressionType(e)
	(* debugging END *)
	|	boxSetDoLambda(e) = raise ErrorBadExpressionType(e)

	and	boxSetScanClosure(body, []) = body
	|	boxSetScanClosure(body, variable :: rest) =
			let
				val currentBody =
					if boxSetNeedsBoxing(variable, body)
						then Seq([boxSetMakeBoxing(variable), boxSetBoxVar(variable, body)])
						else body
			in
				boxSetScanClosure(currentBody, rest)
			end

	and	boxSetNeedsBoxing(variable, expression) =
			boxSetHaveBoundOccurence(variable, false, expression) andalso boxSetIsModified(variable, expression)

	and	boxSetHaveBoundOccurence(variable, _, Abs(args, body)) =
			if SetOps.is_member(variable, args)
				then false
				else boxSetHaveBoundOccurence(variable, true, body)
	|	boxSetHaveBoundOccurence(variable, _, AbsOpt(args, argOpt, body)) =
			if SetOps.is_member(variable, argOpt :: args)
				then false
				else boxSetHaveBoundOccurence(variable, true, body)
	|	boxSetHaveBoundOccurence(variable, _, AbsVar(argList, body)) =
			if SetOps.is_member(variable, [argList])
				then false
				else boxSetHaveBoundOccurence(variable, true, body)
	|	boxSetHaveBoundOccurence(variable, true, Var(name)) = (variable = name)

	|	boxSetHaveBoundOccurence(variable, isBound, If(test, resTrue, resFalse)) = boxSetHaveBoundOccurence(variable, isBound, test)
			orelse boxSetHaveBoundOccurence(variable, isBound, resTrue) orelse boxSetHaveBoundOccurence(variable, isBound, resFalse)
	|	boxSetHaveBoundOccurence(variable, isBound, App(f, args)) = ormap (boxSetHaveBoundOccurenceCurried(variable, isBound)) (f :: args)
	|	boxSetHaveBoundOccurence(variable, isBound, Seq(expressions)) = ormap (boxSetHaveBoundOccurenceCurried(variable, isBound)) expressions
	|	boxSetHaveBoundOccurence(variable, isBound, Or(expressions)) = ormap (boxSetHaveBoundOccurenceCurried(variable, isBound)) expressions
	|	boxSetHaveBoundOccurence(variable, isBound, Set(name, value)) =
			boxSetHaveBoundOccurence(variable, isBound, name) orelse boxSetHaveBoundOccurence(variable, isBound, value)
	|	boxSetHaveBoundOccurence(variable, isBound, Def(name, value)) =
			boxSetHaveBoundOccurence(variable, isBound, name) orelse boxSetHaveBoundOccurence(variable, isBound, value)
	(* debugging START *)
	|	boxSetHaveBoundOccurence(_, _, e as VarFree(_)) = raise ErrorBadExpressionType(e)
	|	boxSetHaveBoundOccurence(_, _, e as VarParam(_, _)) = raise ErrorBadExpressionType(e)
	|	boxSetHaveBoundOccurence(_, _, e as VarBound(_, _, _)) = raise ErrorBadExpressionType(e)
	|	boxSetHaveBoundOccurence(_, _, e as AppTP(_, _)) = raise ErrorBadExpressionType(e)
	(* debugging END *)
	|	boxSetHaveBoundOccurence(_, _, _) = false (* includes Var when isBound = false *)

	and	boxSetHaveBoundOccurenceCurried(variable, isBound) = (fn (x) => boxSetHaveBoundOccurence(variable, isBound, x))

	and	boxSetIsModified(variable, Set(Var(name), value)) =
			if variable = name
				then true
				else boxSetIsModified(variable, value)
	|	boxSetIsModified(variable, Abs(args, body)) =
			if SetOps.is_member(variable, args)
				then false
				else boxSetIsModified(variable, body)
	|	boxSetIsModified(variable, AbsOpt(args, argOpt, body)) =
			if SetOps.is_member(variable, argOpt :: args)
				then false
				else boxSetIsModified(variable, body)
	|	boxSetIsModified(variable, AbsVar(argList, body)) =
			if SetOps.is_member(variable, [argList])
				then false
				else boxSetIsModified(variable, body)
	|	boxSetIsModified(variable, If(test, resTrue, resFalse)) = boxSetIsModified(variable, test) orelse
			boxSetIsModified(variable, resTrue) orelse boxSetIsModified(variable, resFalse)
	|	boxSetIsModified(variable, App(f, args)) = ormap (boxSetIsModifiedCurried(variable)) (f :: args)
	|	boxSetIsModified(variable, Seq(expressions)) = ormap (boxSetIsModifiedCurried(variable)) expressions
	|	boxSetIsModified(variable, Or(expressions)) = ormap (boxSetIsModifiedCurried(variable)) expressions
	|	boxSetIsModified(variable, Set(name, value)) =
			boxSetIsModified(variable, name) orelse boxSetIsModified(variable, value)
	|	boxSetIsModified(variable, Def(name, value)) =
			boxSetIsModified(variable, name) orelse boxSetIsModified(variable, value)
	(* debugging START *)
	|	boxSetIsModified(_, e as VarFree(_)) = raise ErrorBadExpressionType(e)
	|	boxSetIsModified(_, e as VarParam(_, _)) = raise ErrorBadExpressionType(e)
	|	boxSetIsModified(_, e as VarBound(_, _, _)) = raise ErrorBadExpressionType(e)
	|	boxSetIsModified(_, e as AppTP(_, _)) = raise ErrorBadExpressionType(e)
	(* debugging END *)
	|	boxSetIsModified(_, _) = false

	and	boxSetIsModifiedCurried(variable) = (fn (x) => boxSetIsModified(variable, x))

	and	boxSetBoxVar(variable, e as Var(name)) =
			if (variable = name)
				then boxSetMakeGetter(e)
				else e
	|	boxSetBoxVar(variable, Set(v as Var(name), value)) =
			if (variable = name)
				then boxSetMakeSetter(Var(name), boxSetBoxVar(variable, value))
				else Set(v, boxSetBoxVar(variable, value))
	|	boxSetBoxVar(variable, e as Abs(args, body)) =
			if SetOps.is_member(variable, args)
				then e
				else Abs(args, boxSetBoxVar(variable, body))
	|	boxSetBoxVar(variable, e as AbsOpt(args, argOpt, body)) =
			if SetOps.is_member(variable, argOpt :: args)
				then e
				else AbsOpt(args, argOpt, boxSetBoxVar(variable, body))
	|	boxSetBoxVar(variable, e as AbsVar(argList, body)) =
			if SetOps.is_member(variable, [argList])
				then e
				else AbsVar(argList, boxSetBoxVar(variable, body))

	|	boxSetBoxVar(variable, If(test, resTrue, resFalse)) = If(boxSetBoxVar(variable, test), boxSetBoxVar(variable, resTrue),
			boxSetBoxVar(variable, resFalse))
	|	boxSetBoxVar(variable, App(f, args)) = App(boxSetBoxVar(variable, f), map (boxSetBoxVarCurried(variable)) args)
	|	boxSetBoxVar(variable, Seq(expressions)) = Seq(map (boxSetBoxVarCurried(variable)) expressions)
	|	boxSetBoxVar(variable, Or(expressions)) = Or(map (boxSetBoxVarCurried(variable)) expressions)
	|	boxSetBoxVar(variable, Set(name, value)) =
			Set(boxSetBoxVar(variable, name), boxSetBoxVar(variable, value))
	|	boxSetBoxVar(variable, Def(name, value)) =
			Def(boxSetBoxVar(variable, name), boxSetBoxVar(variable, value))
	(* debugging START *)
	|	boxSetBoxVar(_, e as VarFree(_)) = raise ErrorBadExpressionType(e)
	|	boxSetBoxVar(_, e as VarParam(_, _)) = raise ErrorBadExpressionType(e)
	|	boxSetBoxVar(_, e as VarBound(_, _, _)) = raise ErrorBadExpressionType(e)
	|	boxSetBoxVar(_, e as AppTP(_, _)) = raise ErrorBadExpressionType(e)
	(* debugging END *)
	|	boxSetBoxVar(_, e) = e

	and	boxSetBoxVarCurried(variable) = (fn (x) => boxSetBoxVar(variable, x))

	and	boxSetMakeSetter(name as Var(_), value) = App(Var("vector-set!"), [name, Const (Number (0)), value])
	|	boxSetMakeSetter(e, _) = raise ErrorBadExpressionType(e)

	and	boxSetMakeGetter(name as Var(_)) = App(Var("vector-ref"), [name, Const (Number (0))])
	|	boxSetMakeGetter(e) = raise ErrorBadExpressionType(e)

	and	boxSetMakeBoxing(name) = Set(Var(name), App(Var("box"), [Var(name)]))



	fun annotateTC(App(f, args)) = AppTP(annotateTCLambdaOnly(f), map annotateTCLambdaOnly args)
	|	annotateTC(e) = annotateTCTreeWalk(e)

	and	annotateTCTreeWalk(If(test, resTrue, resFalse)) = If(annotateTCLambdaOnly(test), annotateTC(resTrue), annotateTC(resFalse))
	|	annotateTCTreeWalk(Seq(expressions)) = Seq(annotateTCList(expressions, annotateTC))
	|	annotateTCTreeWalk(Or(expressions)) = Or(annotateTCList(expressions, annotateTC))
	|	annotateTCTreeWalk(Set(name, value)) = Set(annotateTCLambdaOnly(name), annotateTCLambdaOnly(value))
	|	annotateTCTreeWalk(Def(name, value)) = Def(annotateTCLambdaOnly(name), annotateTCLambdaOnly(value))
	|	annotateTCTreeWalk(e) = annotateTCLambdaOnly(e)

	and	annotateTCLambdaOnly(Abs(args, body)) = Abs(args, annotateTC(body))
	|	annotateTCLambdaOnly(AbsOpt(args, argOpt, body)) = AbsOpt(args, argOpt, annotateTC(body))
	|	annotateTCLambdaOnly(AbsVar(argList, body)) = AbsVar(argList, annotateTC(body))
	|	annotateTCLambdaOnly(App(f, args)) = App(annotateTCLambdaOnly(f), map annotateTCLambdaOnly args)
	|	annotateTCLambdaOnly(e) = annotateTCLambdaOnlyTreeWalk(e)

	and	annotateTCLambdaOnlyTreeWalk(If(test, resTrue, resFalse)) = If(test, annotateTCLambdaOnly(resTrue), annotateTCLambdaOnly(resFalse))
	|	annotateTCLambdaOnlyTreeWalk(Seq(expressions)) = Seq(annotateTCList(expressions, annotateTCLambdaOnly))
	|	annotateTCLambdaOnlyTreeWalk(Or(expressions)) = Or(annotateTCList(expressions, annotateTCLambdaOnly))
	|	annotateTCLambdaOnlyTreeWalk(Set(name, value)) = Set(annotateTCLambdaOnly(name), annotateTCLambdaOnly(value))
	|	annotateTCLambdaOnlyTreeWalk(Def(name, value)) = Def(annotateTCLambdaOnly(name), annotateTCLambdaOnly(value))
	(* debugging START *)
	|	annotateTCLambdaOnlyTreeWalk(e as Abs(_, _)) = raise ErrorBadExpressionType(e)
	|	annotateTCLambdaOnlyTreeWalk(e as AbsOpt(_, _, _)) = raise ErrorBadExpressionType(e)
	|	annotateTCLambdaOnlyTreeWalk(e as AbsVar(_, _)) = raise ErrorBadExpressionType(e)

	|	annotateTCLambdaOnlyTreeWalk(e as VarFree(_)) = raise ErrorBadExpressionType(e)
	|	annotateTCLambdaOnlyTreeWalk(e as VarParam(_, _)) = raise ErrorBadExpressionType(e)
	|	annotateTCLambdaOnlyTreeWalk(e as VarBound(_, _, _)) = raise ErrorBadExpressionType(e)

	|	annotateTCLambdaOnlyTreeWalk(e as AppTP(_, _)) = raise ErrorBadExpressionType(e)
	(* debugging END *)
	|	annotateTCLambdaOnlyTreeWalk(e) = e

	and	annotateTCList([e], annotator) = [annotator(e)]
	|	annotateTCList(head :: tail, annotator) = annotateTCLambdaOnly(head) :: annotateTCList(tail, annotator)
	|	annotateTCList([], _) = [] ;



	fun	lexicalAddressing(e) = lexicalAddressing'([], e)

	and	lexicalAddressing'(env, Abs(args, body)) = Abs(args, lexicalAddressing'(args :: env, body))
	|	lexicalAddressing'(env, AbsOpt(args, argOpt, body)) = AbsOpt(args, argOpt, lexicalAddressing'((args @ [argOpt]) :: env, body))
	|	lexicalAddressing'(env, AbsVar(argList, body)) = AbsVar(argList, lexicalAddressing'([argList] :: env, body))
	|	lexicalAddressing'(env, Var(name)) =
			lexicalAddressingFindVar(
				name,
				env,
				0,
				(fn	(false, _, _) => VarFree(name)
				|	(true, 0, minor) => VarParam(name, minor)
				|	(true, major, minor) => VarBound(name, major-1, minor))
			)
	|	lexicalAddressing'(env, e) = lexicalAddressingTreeWalk(env, e)

	and	lexicalAddressingFindVar(_, [], major, continuation) = continuation(false, 0, 0)
	|	lexicalAddressingFindVar(name, args :: externalEnv, major, continuation) =
			let
				val minor = ListOps.search(name, args)
			in
				if minor >= 0
					then continuation(true, major, minor)
					else lexicalAddressingFindVar(name, externalEnv, major+1, continuation)
			end

	and	lexicalAddressingTreeWalk(env, If(test, resTrue, resFalse)) =
			If(
				lexicalAddressing'(env, test),
				lexicalAddressing'(env, resTrue),
				lexicalAddressing'(env, resFalse)
			)
	|	lexicalAddressingTreeWalk(env, App(f, args)) =
			App(
				lexicalAddressing'(env, f),
				map (lexicalAddressingFixedEnv(env)) args
			)
	|	lexicalAddressingTreeWalk(env, AppTP(f, args)) =
			AppTP(
				lexicalAddressing'(env, f),
				map (lexicalAddressingFixedEnv(env)) args
			)
	|	lexicalAddressingTreeWalk(env, Seq(expressions)) = Seq(map (lexicalAddressingFixedEnv(env)) expressions)
	|	lexicalAddressingTreeWalk(env, Or(expressions)) = Or(map (lexicalAddressingFixedEnv(env)) expressions)
	|	lexicalAddressingTreeWalk(env, Set(name, value)) = Set(lexicalAddressing'(env, name), lexicalAddressing'(env, value))
	(* 'define' does not change the original variable, what do we do? *)
(* 	|	lexicalAddressingTreeWalk(env, Def(name, value)) = Def(name, lexicalAddressing'(env, value)) *)
	|	lexicalAddressingTreeWalk(env, Def(name, value)) = Def(lexicalAddressing'(env, name), lexicalAddressing'(env, value)) (* temp *)
	(* debugging START *)
	|	lexicalAddressingTreeWalk(_, e as Abs(_, _)) = raise ErrorBadExpressionType(e)
	|	lexicalAddressingTreeWalk(_, e as AbsOpt(_, _, _)) = raise ErrorBadExpressionType(e)
	|	lexicalAddressingTreeWalk(_, e as AbsVar(_, _)) = raise ErrorBadExpressionType(e)
	|	lexicalAddressingTreeWalk(_, e as Var(_)) = raise ErrorBadExpressionType(e)

	|	lexicalAddressingTreeWalk(_, e as VarFree(_)) = raise ErrorBadExpressionType(e)
	|	lexicalAddressingTreeWalk(_, e as VarParam(_, _)) = raise ErrorBadExpressionType(e)
	|	lexicalAddressingTreeWalk(_, e as VarBound(_, _, _)) = raise ErrorBadExpressionType(e)
	(* debugging END *)
	|	lexicalAddressingTreeWalk(_, e) = e

	and	lexicalAddressingFixedEnv(env) = fn (e) => lexicalAddressing'(env, e) ;



	val	semanticAnalysis = lexicalAddressing o annotateTC o boxSet o convertAbsVarToAbsOpt o removeNestedDefine;
end;


